Fixes #5239. AOT configuration initialization crash#5240
Conversation
Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/275ee9b0-ace3-402a-a75e-18ca75db4388 Co-authored-by: tig <585482+tig@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes an AOT startup crash in ConfigurationManager.Initialize by avoiding reflection-based cloning of Dictionary<Command, PlatformKeyBinding> (which can fail after trimming removes the closed generic ctor). The PR introduces a typed deep-clone path for key binding dictionaries and adds a regression test asserting cached defaults are independent copies.
Changes:
- Replaced
DeepCloner.DeepClone(...)with a typed cloning path forDictionary<Command, PlatformKeyBinding>during hard-coded configuration cache initialization. - Implemented deep-copy logic for
PlatformKeyBindingand nestedKey[]arrays while preserving the dictionary comparer. - Added a non-parallelizable test covering deep-copy independence of the cached key binding dictionaries.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| Terminal.Gui/Configuration/ConfigurationManager.cs | Adds typed cloning for key binding dictionaries to avoid reflection/trim issues under AOT. |
| Tests/UnitTests.NonParallelizable/Configuration/ConfigurationMangerTests.cs | Adds regression test ensuring cached hard-coded key binding dictionaries are deep copies. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/d1e76594-a3c8-4c84-b738-3decfdb73987 Co-authored-by: tig <585482+tig@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/d1e76594-a3c8-4c84-b738-3decfdb73987 Co-authored-by: tig <585482+tig@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/094cf268-64cd-42e9-9179-af0d70e786a2 Co-authored-by: tig <585482+tig@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
I had 4 different agents review this and I ran tests exhausively. I'm going to break the rule of having another maintainer review it becauswe I need it integrated now so I can make progress on validating AOT with clet. |
* Initial plan * Fix AOT hard-coded key binding clone Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/275ee9b0-ace3-402a-a75e-18ca75db4388 Co-authored-by: tig <585482+tig@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Match nullable key array test helper Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/d1e76594-a3c8-4c84-b738-3decfdb73987 Co-authored-by: tig <585482+tig@users.noreply.github.com> * Use precise nullable warning suppression Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/d1e76594-a3c8-4c84-b738-3decfdb73987 Co-authored-by: tig <585482+tig@users.noreply.github.com> * Use record with expression for key binding clone Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/094cf268-64cd-42e9-9179-af0d70e786a2 Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add AOT-safety comment to CloneHardCodedPropertyValue Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tig <585482+tig@users.noreply.github.com> Co-authored-by: Tig <tig@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
No problem. Feel free because you know very well what you're doing, and very well. Often we don't have access to a laptop either. But I saw the PR just now and they actually adopted a very clever solution by only forcing deep cloning on untreated cases and speed cloning on the remaining cases. |
The fix from #5243 ("Fixes #5259. AOT: use source-generated JSON serializer for dictionary construction in DeepCloner") was reverted when release/v2.1.0-rc.1 merged origin/main back at 94dca98. That merge had conflicts in DeepCloner.cs and ConfigurationManager.cs and the resolution picked main's pre-#5243 versions, dropping: - 27 lines from DeepCloner.cs (the SourceGenerationContext.GetTypeInfo fallback in CreateDictionaryInstance, plus its leading comment) and re-adding 54 lines to ConfigurationManager.cs: - CloneHardCodedPropertyValue and the per-type clone helpers (CloneKeyBindings, ClonePlatformKeyBinding, CloneKeyArray) that #5243 had removed in favor of generic DeepCloner handling - the call site change from DeepClone to CloneHardCodedPropertyValue PRs #5246 (rc.1 → main) and #5247 (rc.1 backmerge → develop) carried the broken state forward. v2.1.0-beta.1 was tagged before the merge (no fix); v2.1.0-rc.1 was tagged after but doesn't have it either. Repro: `dotnet publish Examples/NativeAot -c Release -r win-x64 --self-contained -p:PublishAot=true` against current develop crashes at module init with `MissingMethodException: No parameterless constructor defined for type Dictionary<ColorName16, string>`. Same crash a downstream AOT consumer (clet) hit and tracked as #5239 → #5240 → #5242 → #5243 → #5248. This commit checks DeepCloner.cs and ConfigurationManager.cs out of 11d6e27 (the original PR #5243 merge), restoring the source-gen fallback and removing the per-type helpers. Verified locally: - `dotnet build Terminal.Gui/Terminal.Gui.csproj -c Release` → 0 errors - clet AOT publish + `clet.exe --version` runs cleanly (was crashing against rc.1; now exits 0 with the local TG nupkg pinned) Refs #5239, #5242, #5243, #5248, #5259. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes
AOT-published apps could crash before
Mainbecause configuration initialization deep-clonedDictionary<Command, PlatformKeyBinding>via reflective construction after trimming removed the closed generic default constructor.Proposed Changes/Todos
DeepClonerreflection.PlatformKeyBindingentries and nestedKey []arrays while preserving the dictionary comparer.withexpression when cloningPlatformKeyBindingso future record properties are preserved.PlatformKeyBindingproperties.Pull Request checklist:
CTRL-K-Dto automatically reformat your files before committing.dotnet testbefore commit///style comments)